#include "c_precompiled.h"
#include "sv_local.h"

template<> ServerSystem* Ogre::Singleton<ServerSystem>::ms_Singleton=0;
ServerSystem server_static_singleton;

ServerSystem::ServerSystem(){
	
}
ServerSystem::~ServerSystem(){
	shutdown();
}

void ServerSystem::init(unsigned port){
	startServer(port);
}
void ServerSystem::shutdown(){
	stopServer();
}
void ServerSystem::update(){
	//check incoming connections, read packets etc..
	manageServerSocket();
}

void ServerSystem::startServer(unsigned port){
	ENetAddress address;

    address.host = ENET_HOST_ANY;
	address.port = port;

    mServerSocket = enet_host_create (& address /* the address to bind the server host to */, 
                                 32      /* allow up to 32 clients and/or outgoing connections */,
                                  0      /* assume any amount of incoming bandwidth */,
                                  0      /* assume any amount of outgoing bandwidth */);
    if (!mServerSocket)
		throw Ogre::Exception(0,"Could not start server!","ServerSystem::startServer()");
}
void ServerSystem::stopServer(){
	if(mServerSocket)
		enet_host_destroy(mServerSocket);
	mServerSocket=0;
}
void ServerSystem::manageServerSocket(){
	ENetEvent event;
    SVActor *actor=0;//used for connection events
	std::vector<SVActor*>::iterator it;
	ByteBuffer packet(LIMIT_PACKETSIZE);
    while (enet_host_service (mServerSocket, & event, 0) > 0)
    {
        switch (event.type)
        {
        case ENET_EVENT_TYPE_CONNECT:
			printlog("Client has connected to the server!");
			//a new client connected to the server so we have to allocate an actor (manager)
			//for this client...
			actor=new SVActor(event.peer);
			//we also store a pointer back to actor that owns this peer
			event.peer->data=actor;
			mActors.push_back(actor);
            break;
        case ENET_EVENT_TYPE_RECEIVE:
			packet.writeData(event.packet->data,event.packet->dataLength);
			actor=(SVActor*)event.peer->data;
			if(actor)
				actor->decodeNetworkPacket(packet);
			//delete the packet now that we are done with it
            enet_packet_destroy (event.packet);
            break;
        case ENET_EVENT_TYPE_DISCONNECT:
			printlog("Client disconnected!");
            //remove actor that is connected to this peer from the list and delete it
			actor=(SVActor*)event.peer->data;
			for(it=mActors.begin();it!=mActors.end();it++){
				if((*it)==actor){
					mActors.erase(it);
					delete actor;
					break;
				}
			}
			break;
        }
    }
}
Server &Server::getSingleton(){
	return ServerSystem::getSingleton();
}
Server *Server::getSingletonPtr(){
	return ServerSystem::getSingletonPtr();
}